package com.zkh.myutils.bean;

import java.lang.reflect.Array;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.function.BiFunction;

import com.zkh.myutils.utils.ArrayUtils;

/**
 * 数组/集合转换器
 * @author zkh
 */
public class BeanArrayConverter {

	/**
	 * 集合类型
	 */
	public static List<String> collectionType = Arrays.asList(
		"java.util.Collection", "java.util.List", "java.util.ArrayList", "java.util.LinkedList", "java.util.Vector", 
		"java.util.Set", "java.util.HashSet", "java.util.TreeSet", "java.util.Arrays$ArrayList"
	);

	/**
	 * 将值value转换为集合
	 * @param value 待转换的值
	 * @param fromTypeClass 待转换的值类型Class
	 * @param toTypeClass 目标字段类型Class
	 * @param genericType 泛型类型
	 * @return 转换后的值
	 */
	public static Object toList(Object value, Class<?> fromTypeClass, Class<?> toTypeClass, String genericType){
		return toList(value, fromTypeClass, toTypeClass, genericType, null, null);
	}
	
	/**
	 * 将值value转换为集合
	 * @param value 待转换的值
	 * @param fromTypeClass 待转换的值类型Class
	 * @param toTypeClass 目标字段类型Class
	 * @param genericType 泛型类型
	 * @param targetTypeClass 集合项类型
	 * @param converterManager 转换器管理器
	 * @return 转换后的值
	 */
	public static Object toList(Object value, Class<?> fromTypeClass, Class<?> toTypeClass, String genericType, 
			Class<?> targetTypeClass, TypeConverterManager converterManager) {
		return toList(value, fromTypeClass, fromTypeClass.getName(), toTypeClass, toTypeClass.getName(), genericType, targetTypeClass, converterManager);
	}
	
	/**
	 * 将值value转换为集合
	 * @param value 待转换的值
	 * @param fromTypeClass 待转换的值类型Class
	 * @param fromTypeName 待转换的值类型名称
	 * @param toTypeClass 目标字段类型Class
	 * @param toTypeName 目标字段类型名称
	 * @param genericType 泛型类型
	 * @return 转换后的值
	 */
	public static Object toList(Object value, Class<?> fromTypeClass, String fromTypeName,
			Class<?> toTypeClass, String toTypeName, String genericType) {
		return toList(value, fromTypeClass, fromTypeName, toTypeClass, toTypeName, genericType, null, null);
	}


	/**
	 * 将值value转换为集合
	 * @param value 待转换的值
	 * @param fromTypeClass 待转换的值类型Class
	 * @param fromTypeName 待转换的值类型名称
	 * @param toTypeClass 目标字段类型Class
	 * @param toTypeName 目标字段类型名称
	 * @param genericType 泛型类型
	 * @param targetTypeClass 集合项类型
	 * @param converterManager 转换器管理器
	 * @return 转换后的值
	 */
	public static Object toList(Object value, Class<?> fromTypeClass, String fromTypeName, Class<?> toTypeClass, String toTypeName, String genericType, 
			Class<?> targetTypeClass, TypeConverterManager converterManager) {
		//下层泛型类型
		String nextGenericType=null;
		//集合项的类型
		String targetItemTypeName=null;
		//集合项类型
		Class<?> targetItemTypeClass=null;
		//泛型标识
		int idx = genericType==null ? -1 : genericType.indexOf('<');
		//没有泛型
		if(idx==-1){
			targetItemTypeClass = targetTypeClass==null ? Object.class : targetTypeClass;
		}//获取泛型
		else{
			//获取泛型（对象、数组、List集合、Map集合）
			genericType = genericType.substring(idx+1, genericType.lastIndexOf('>'));
			//查找泛型
			idx = genericType.indexOf('<');
			//还有下级泛型
			if(idx>-1) {
				//保存类型
				targetItemTypeName = genericType.substring(0, idx);
				//保存泛型
				nextGenericType = genericType;
			}//数组（含多重）
			else if(genericType.endsWith("[]")) {
				//截取类型
				String type = genericType.substring(0, genericType.indexOf('['));
				//判断基础类型
				String tempType = BeanUtils.BASE_DESC_MAP.get(type);
				//不是基础类型
				if(tempType==null) {
					tempType = "L" + type + ";";
				}
				//获取数组维度
				int len = (genericType.length() - type.length())/2;
				//遍历拼接类型
				for(int i=0; i<len; i++) {
					tempType = "[" + tempType;
				}
				//保存类型
				targetItemTypeName = tempType;
			}//其它均视为对象
			else {
				targetItemTypeName = genericType;
			}
			//处理泛型为?，以传入的类型为主，否则默认Object
			if("?".equals(targetItemTypeName)) {
				targetItemTypeClass = targetTypeClass==null ? Object.class : targetTypeClass;
				targetItemTypeName = null;
			}
			//有指定类型
			else if(targetTypeClass!=null) {
				//和指定类型不匹配
				if(!targetTypeClass.getName().equals(targetItemTypeName)) {
					throw new TypeConverterException("指定集合项类型（"+targetTypeClass.getName()+"）与泛型解析的类型不一致：" + targetItemTypeName);
				}
				//直接使用指定类型
				targetItemTypeClass = targetTypeClass;
				targetItemTypeName = null;
			}
		}
		try{
			//实例化
			if(targetItemTypeName!=null) {
				targetItemTypeClass = Class.forName(targetItemTypeName);
			}
		}catch (ClassNotFoundException e){
			throw new TypeConverterException("不存在的类：" + targetItemTypeName, e);
		}
		//创建目标集合容器
		return commonConvert(value, fromTypeClass, fromTypeName, toTypeClass, toTypeName, targetItemTypeClass, true, nextGenericType, converterManager, (titc,len)->{
			if(Set.class.isAssignableFrom(toTypeClass)){
				return new HashSet<>();
			}
			if(toTypeClass.isInterface()){
				return new ArrayList<>();
			}
			try{
				return toTypeClass.newInstance();
			}catch (InstantiationException | IllegalAccessException e){
				throw new TypeConverterException("集合" + toTypeName + "实例化失败", e);
			}
		});
	}


	/**
	 * 将值value转换为数组
	 * @param value 待转换的值
	 * @param fromTypeClass 待转换的值类型Class
	 * @param toTypeClass 目标字段类型Class
	 * @return 转换后的数据
	 */
	public static Object toArray(Object value, Class<?> fromTypeClass, Class<?> toTypeClass){
		return toArray(value, fromTypeClass, fromTypeClass.getName(), toTypeClass, toTypeClass.getName());
	}

	/**
	 * 将值value转换为数组
	 * @param value 待转换的值
	 * @param fromTypeClass 待转换的值类型Class
	 * @param fromTypeName 待转换的值类型名称
	 * @param toTypeClass 目标字段类型Class
	 * @param toTypeName 目标字段类型名称
	 * @return 转换后的数据
	 */
	public static Object toArray(Object value, Class<?> fromTypeClass, String fromTypeName, Class<?> toTypeClass, String toTypeName) {
		//获取目标元素项的类型Class（getComponentType用来获取数组项的Class，可以直接创建数组）
		Class<?> targetItemTypeClass = toTypeClass.getComponentType();
		//创建目标数组容器
		return commonConvert(value, fromTypeClass, fromTypeName, toTypeClass, toTypeName, targetItemTypeClass, false, null, null, Array::newInstance);
	}

	/**
	 * 将值value转换为数组
	 * @param value 待转换的值
	 * @param fromTypeClass 待转换的值类型Class
	 * @param fromTypeName 待转换的值类型名称
	 * @param toTypeClass 目标字段类型Class
	 * @param toTypeName 目标字段类型名称
	 * @param targetItemTypeClass 目标项类型Class
	 * @param toList 是否转集合，true是转集合，false转数组
	 * @param targetItemGenericType 目标项泛型类型
	 * @param converterManager 转换器管理器
	 * @param container 自定义创建目标容器方法
	 * @return 转换后的数组
	 */
	@SuppressWarnings({"unchecked", "rawtypes"})
	private static Object commonConvert(Object value, Class<?> fromTypeClass, String fromTypeName, Class<?> toTypeClass, String toTypeName, Class<?> targetItemTypeClass, boolean toList,
			String targetItemGenericType, TypeConverterManager converterManager, BiFunction<Class<?>, Integer, Object> container){
		//值为空，或数组类型相同，直接返回值
		if(value==null || !toList && fromTypeName.equals(toTypeName)){
			return value;
		}
		//值是否为集合/数组
		boolean isArr = fromTypeClass.isArray();
		boolean isColl = collectionType.contains(fromTypeName);
		//值不是数组也不是集合，不能转换
		if(!isArr && !isColl){
			throw new TypeConverterException(fromTypeName+"不能转换为"+toTypeName+"类型");
		}
		//长度
		int len = isArr ? Array.getLength(value) : ((Collection<?>) value).size();
		//目标元素项的类型Class
		String targetItemTypeName = targetItemTypeClass.getName();
		//创建目标容器
		Object result = container.apply(targetItemTypeClass, len);
		//自定义解析器
		TypeConverter<?> converter = converterManager==null ? null : converterManager.getConverter(targetItemTypeClass);
		//为空
		if(converter==null) {
			converter = BeanUtils.globalConverterManager.getConverter(targetItemTypeClass);
		}
		//整体类型标识
		boolean wholeConverter = WholeTypeConverter.TYPE_WHOLE_LIST.contains(targetItemTypeName);
		//将源数组格式的数据转为集合方便统一处理
		Collection<?> origins = isColl ? (Collection<?>) value : Arrays.asList(ArrayUtils.getArray(value));
		//计数
		int count = 0;
		//遍历源数据
		for(Object val: origins){
			//值不为空
			if(val!=null) {
				//源类型（考虑到继承关系，可能每项元素的真实类型都不相同（相同父类），所以每次需要实时获取类型）
				Class<?> originTypeClass = val.getClass();
				String originTypeName = originTypeClass.getName();
				//转换后的值
				Object v;
				//集合List和数组转换（可转集合和数组）
				if(collectionType.contains(originTypeName) || originTypeClass.isArray()){
					//转数组
					if(targetItemTypeClass.isArray()){
						v = toArray(val, originTypeClass, targetItemTypeClass);
					}//转集合
					else if(collectionType.contains(targetItemTypeName)){
						v = toList(val, originTypeClass, originTypeName, targetItemTypeClass, targetItemTypeName, targetItemGenericType, null, converterManager);
					}else{
						throw new IllegalArgumentException(originTypeName + "类型不能转换为" + toTypeName + "类型");
					}
				}
				//类型相同或为Object，直接保存
				else if (originTypeClass.getName().equals(toTypeName) || toTypeClass.isAssignableFrom(originTypeClass) || Type.OBJECT.equals(targetItemTypeName)) {
					v = val;
				}//整体类型
				else if (wholeConverter) {
					v = WholeTypeConverter.cast(val, originTypeName, targetItemTypeName);
				}//有转换器
				else if (converter != null) {
					v = converter.convertToProperty(val);
				}//Map对象
				else if (val instanceof Map) {
					v = BeanUtils.mapToBean((Map<String, ?>) val, targetItemTypeClass);
				} else {
					throw new TypeConverterException("类型" + originTypeName + "无法转换为类型" + targetItemTypeName);
				}
				//如果是集合
				if (result instanceof Collection) {
					((Collection) result).add(v);
				}//数组
				else {
					//保存值
					Array.set(result, count++, v);
				}
			}
		}
		//返回最终结果值
		return result;
	}
}
